package xddq

import (
	"fmt"
	"math/rand"
)

/*
请帮我完善以上代码，有点像2048的合成游戏，有以下规则

1：要求每次移动尽量不要移动等级合最高的一行，可以考虑Z字形规则（即不移动最下一行），例如以下
0 1 2 3
7 6 5 4
8 9 10 11
15 14 13 12
2：同时在上面的基础上预测未来2步得分最多的移动方向。
3：当发现移动后没有加分时，在确保高等级不变化的情况下可以随意移动
Z字型规则的具体描述是，例如以左下角为起点，那么最开始尽量只不要右移，在最后一行填满后（左右移动不会改变）的基础上，开始倒数第2行的填充。
其中倒数第二行可以尽量合并倒数第一行，如果不能升级合并则保证从左往右依次变大，在保证倒数第一行左右移动不变的情况下，尽量少左移，以此类推
*/
const (
	LQDH_UP = iota
	LQDH_DOWN
	LQDH_LEFT
	LQDH_RIGHT
)

var moveDesc = []string{"↑↑↑↑上", "↓↓↓↓下", "←←←←左", "→→→→右"}

type Game struct {
	board [][]int
	score int64
}

func boardEqual(board1, board2 [][]int) bool {
	for i := 0; i < len(board1); i++ {
		for j := 0; j < len(board1[i]); j++ {
			if board1[i][j] != board2[i][j] {
				return false
			}
		}
	}
	return true
}

func printBoard(board [][]int) {
	fmt.Println()
	for _, row := range board {
		for _, num := range row {
			if num == 0 {
				fmt.Printf("%4s", ".") // 用点表示空格
			} else {
				fmt.Printf("%4d", num) // 格式化输出数字
			}
		}
		fmt.Println()
	}
	fmt.Println()
}

func NewGame() *Game {
	board := make([][]int, 4)
	for i := range board {
		board[i] = make([]int, 4)
	}
	game := &Game{board: board}
	game.addRandomTile()
	game.addRandomTile()
	return game
}

// calculateScore 计算给定棋盘的得分
func (g *Game) calculateScore(board [][]int) int64 {
	score := int64(0)
	for i := 0; i < 4; i++ {
		for j := 0; j < 4; j++ {
			if board[i][j] != 0 {
				score += 1 << int64(board[i][j]) // 累加合并得分
			}
		}
	}
	return score
}

func (g *Game) addRandomTile() bool {
	emptyTiles := []struct{ row, col int }{}
	maxValue := 1
	for i := 0; i < 4; i++ {
		for j := 0; j < 4; j++ {
			if g.board[i][j] == 0 {
				emptyTiles = append(emptyTiles, struct{ row, col int }{i, j})
			}
			if g.board[i][j] > maxValue {
				maxValue = g.board[i][j]
			}
		}
	}
	if len(emptyTiles) == 0 {
		return false
	}
	newValue := rand.Intn(maxValue) + 1
	tile := emptyTiles[rand.Intn(len(emptyTiles))]
	g.board[tile.row][tile.col] = newValue
	return true
}

func (g *Game) move(direction int) bool {
	tempBoard := make([][]int, len(g.board))
	for i := range tempBoard {
		tempBoard[i] = make([]int, len(g.board[i]))
		copy(tempBoard[i], g.board[i])
	}

	g.moveBoard(g.board, direction)
	if !boardEqual(g.board, tempBoard) {
		g.addRandomTile()
		return true
	}
	return false
}

func (g *Game) moveBoard(board [][]int, move int) bool {
	moved := false
	switch move {
	case LQDH_UP:
		moved = g.moveUp(board)
	case LQDH_DOWN:
		moved = g.moveDown(board)
	case LQDH_LEFT:
		moved = g.moveLeft(board)
	case LQDH_RIGHT:
		moved = g.moveRight(board)
	}
	return moved
}

func (g *Game) isGameOver() bool {
	for move := LQDH_UP; move <= LQDH_RIGHT; move++ {
		tempBoard := make([][]int, len(g.board))
		for i := range tempBoard {
			tempBoard[i] = make([]int, len(g.board[i]))
			copy(tempBoard[i], g.board[i])
		}
		g.moveBoard(tempBoard, move)
		if !boardEqual(tempBoard, g.board) {
			return false
		}
	}
	return true
}

func (g *Game) moveUp(board [][]int) bool {
	flag := false
	tmpBoard := make([][]int, 4)
	for i := range tmpBoard {
		tmpBoard[i] = make([]int, 4)
		copy(tmpBoard[i], board[i])
	}

	for col := 0; col < 4; col++ {
		for row := 1; row < 4; row++ {
			if board[row][col] == 0 {
				continue
			}
			for i := row; i > 0; i-- {
				if board[i-1][col] == 0 {
					board[i-1][col] = board[i][col]
					board[i][col] = 0
					flag = true
				} else if board[i-1][col] == board[i][col] {
					board[i-1][col]++
					g.score += 1 << int64(board[i-1][col]) // 增加得分
					board[i][col] = 0
					flag = true
					break
				} else {
					break
				}
			}
		}
	}

	return flag && !boardEqual(tmpBoard, board)
}

func (g *Game) moveDown(board [][]int) bool {
	flag := false
	tmpBoard := make([][]int, 4)
	for i := range tmpBoard {
		tmpBoard[i] = make([]int, 4)
		copy(tmpBoard[i], board[i])
	}

	for col := 0; col < 4; col++ {
		for row := 2; row >= 0; row-- {
			if board[row][col] == 0 {
				continue
			}
			for i := row; i < 3; i++ {
				if board[i+1][col] == 0 {
					board[i+1][col] = board[i][col]
					board[i][col] = 0
					flag = true
				} else if board[i+1][col] == board[i][col] {
					board[i+1][col]++
					g.score += 1 << int64(board[i+1][col]) // 增加得分
					board[i][col] = 0
					flag = true
					break
				} else {
					break
				}
			}
		}
	}

	return flag && !boardEqual(tmpBoard, board)
}

func (g *Game) moveLeft(board [][]int) bool {
	flag := false
	tmpBoard := make([][]int, 4)
	for i := range tmpBoard {
		tmpBoard[i] = make([]int, 4)
		copy(tmpBoard[i], board[i])
	}

	for row := 0; row < 4; row++ {
		for col := 1; col < 4; col++ {
			if board[row][col] == 0 {
				continue
			}
			for i := col; i > 0; i-- {
				if board[row][i-1] == 0 {
					board[row][i-1] = board[row][i]
					board[row][i] = 0
					flag = true
				} else if board[row][i-1] == board[row][i] {
					board[row][i-1]++
					g.score += 1 << int64(board[row][i-1]) // 增加得分
					board[row][i] = 0
					flag = true
					break
				} else {
					break
				}
			}
		}
	}

	return flag && !boardEqual(tmpBoard, board)
}

func (g *Game) moveRight(board [][]int) bool {
	flag := false
	tmpBoard := make([][]int, 4)
	for i := range tmpBoard {
		tmpBoard[i] = make([]int, 4)
		copy(tmpBoard[i], board[i])
	}

	for row := 0; row < 4; row++ {
		for col := 2; col >= 0; col-- {
			if board[row][col] == 0 {
				continue
			}
			for i := col; i < 3; i++ {
				if board[row][i+1] == 0 {
					board[row][i+1] = board[row][i]
					board[row][i] = 0
					flag = true
				} else if board[row][i+1] == board[row][i] {
					board[row][i+1]++
					g.score += 1 << int64(board[row][i+1]) // 增加得分
					board[row][i] = 0
					flag = true
					break
				} else {
					break
				}
			}
		}
	}

	return flag && !boardEqual(tmpBoard, board)
}

func (g *Game) recommendMove() int {
	moves := []int{LQDH_UP, LQDH_DOWN, LQDH_LEFT, LQDH_RIGHT}
	bestMove := -1
	maxScore := int64(0)

	for _, move := range moves {
		tempBoard := g.cloneBoard()
		if g.moveBoard(tempBoard, move) {
			currentScore := g.simulateFutureMoves(tempBoard, 2) // 模拟未来2步
			if currentScore > maxScore {
				maxScore = currentScore
				bestMove = move
			}
		}
	}

	return bestMove
}

// cloneBoard 创建棋盘的深拷贝
func (g *Game) cloneBoard() [][]int {
	tempBoard := make([][]int, len(g.board))
	for i := range tempBoard {
		tempBoard[i] = make([]int, len(g.board[i]))
		copy(tempBoard[i], g.board[i])
	}
	return tempBoard
}

// simulateFutureMoves 模拟未来多步移动的得分
func (g *Game) simulateFutureMoves(board [][]int, depth int) int64 {
	if depth == 0 {
		return g.calculateScore(board)
	}

	maxFutureScore := int64(0)
	moves := []int{LQDH_UP, LQDH_DOWN, LQDH_LEFT, LQDH_RIGHT}

	for _, move := range moves {
		tempBoard := g.cloneBoard()
		if g.moveBoard(tempBoard, move) {
			futureScore := g.simulateFutureMoves(tempBoard, depth-1)
			if futureScore > maxFutureScore {
				maxFutureScore = futureScore
			}
		}
	}

	return maxFutureScore
}
